package com.bingo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bingo.entity.*;
import com.bingo.entity.dto.*;
import com.bingo.entity.dto.req.ReqBody;
import com.bingo.service.*;
import com.bingo.until.IsToday;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Date;
import java.util.LinkedList;
import java.util.List;

/**
 * @author Bingo
 * @version 1.0
 * @description 汇总服务实现类
 * @date 2024/3/21 14:23
 */
@Service
public class SummaryServiceImpl implements SummaryService {
    private HisPoolService hisPoolService;
    @Autowired
    public void setPoolService(HisPoolService hisPoolService) {
        this.hisPoolService = hisPoolService;
    }

    private CurPoolService curPoolService;
    @Autowired
    public void setPrePoolService(CurPoolService curPoolService) {
        this.curPoolService = curPoolService;
    }

    private SiteService siteService;
    @Autowired
    public void setSiteService(SiteService siteService) {
        this.siteService = siteService;
    }

    private FeedLossService feedLossService;
    @Autowired
    public void setFeedLossService(FeedLossService feedLossService) {
        this.feedLossService = feedLossService;
    }

    private PutService putService;
    @Autowired
    public void setPutService(PutService putService) {
        this.putService = putService;
    }

    private ClearLossService clearLossService;
    @Autowired
    public void setClearLossService(ClearLossService clearLossService) {
        this.clearLossService = clearLossService;
    }

    private SaleService saleService;
    @Autowired
    public void setSaleService(SaleService saleService) {
        this.saleService = saleService;
    }

    private DivideService divideService;
    @Autowired
    public void setDivideService(DivideService divideService) {
        this.divideService = divideService;
    }

    private BaseDataService baseDataService;
    @Autowired
    public void setBaseDataService(BaseDataService baseDataService) {
        this.baseDataService = baseDataService;
    }

    @Override
    public List<PoolSummaryDto> PoolSummary(ReqBody reqBody) {
        List<String> poolNos = reqBody.getPoolNos();
        LinkedList<PoolSummaryDto> list = new LinkedList<>();

        if (poolNos == null || poolNos.size() == 0){
            poolNos = curPoolService.getPoolNos();
        }

        for (String poolNo : poolNos) {
            //新建汇总对象
            PoolSummaryDto poolSummaryDto = new PoolSummaryDto();
            poolSummaryDto.setPoolNo(poolNo);
            poolSummaryDto.setKey(poolNo);
            //查询期初状态
            HisPool startHisPool = hisPoolService.getPoolByNoAndDate(poolNo, reqBody.getDate()[0]);
            setStart(poolSummaryDto, startHisPool);
            //查询期末状态
            HisPool endHisPool = null;
            CurPool curPool = null;
            if (IsToday.isToday(reqBody.getDate()[1])) {
                curPool = curPoolService.getCurPoolByNo(poolNo);
                if (curPool == null){
                    continue;
                }
                setPreEnd(poolSummaryDto, curPool);
            } else {
                endHisPool = hisPoolService.getPoolByNoAndDate(poolNo, reqBody.getDate()[1]);
                if (endHisPool == null){
                    continue;
                }
                setEnd(poolSummaryDto, endHisPool);
            }
            //本期投喂增重、日常损耗
            DailyLoss dailyLoss = new DailyLoss();
            dailyLoss.setAmount(0);
            dailyLoss.setWeight(0.0);
            FeedGainWeight feedGainWeight = feedLossService.selectWeightIncrease(poolNo, reqBody.getDate()[0], reqBody.getDate()[1],dailyLoss);
            poolSummaryDto.setFeedGainWeight(feedGainWeight);
            poolSummaryDto.setDailyLoss(dailyLoss);

            //新苗投塘
            NewSeedLings newSeedLings = putService.getNewSeedLings(poolNo, reqBody.getDate()[0], reqBody.getDate()[1]);
            poolSummaryDto.setNewSeedLings(newSeedLings);

            //本期发生
            HappenedInPeriod happenedInPeriod = saleService.summarySale(poolNo, reqBody.getDate()[0], reqBody.getDate()[1]);
            //分塘
            divideService.summaryDivide(poolNo, reqBody.getDate()[0], reqBody.getDate()[1], happenedInPeriod);
            poolSummaryDto.setHappenedInPeriod(happenedInPeriod);


            //清塘亏损
            CleanLoss cleanLoss = clearLossService.selectCleanLoss(poolNo, reqBody.getDate()[0], reqBody.getDate()[1]);
            poolSummaryDto.setCleanLoss(cleanLoss);

            list.add(poolSummaryDto);
        }
        return list;
    }

    //设置期初状态
    private void setStart(PoolSummaryDto poolSummaryDto, HisPool startHisPool) {
        if (startHisPool == null){
            poolSummaryDto.setBeginType(0);
            poolSummaryDto.setArea(0.0);
            Beginning beginning = new Beginning();
            beginning.setAmount(0);
            beginning.setWeight(0.0);
            beginning.setSize(0.0);
            poolSummaryDto.setBeginning(beginning);
        }else {
            poolSummaryDto.setBeginType(startHisPool.getType());
            poolSummaryDto.setArea(startHisPool.getArea());
            Beginning beginning = new Beginning();
            beginning.setAmount(startHisPool.getQuantity());
            beginning.setWeight(startHisPool.getWeight());
            if (startHisPool.getWeight() == 0 || startHisPool.getQuantity() == 0){
                beginning.setSize(0.0);
            } else {
                beginning.setSize(startHisPool.getQuantity()/ startHisPool.getWeight());
            }
            poolSummaryDto.setBeginning(beginning);
        }


    }

    //设置期末状态
    private void setEnd(PoolSummaryDto poolSummaryDto, HisPool endHisPool) {
        poolSummaryDto.setEndType(endHisPool.getType());
        Ending ending = new Ending();
        ending.setAmount(endHisPool.getQuantity());
        ending.setWeight(endHisPool.getWeight());
        if (endHisPool.getWeight() == 0 || endHisPool.getQuantity() == 0){
            ending.setSize(0.0);
        } else {
            ending.setSize(endHisPool.getQuantity()/ endHisPool.getWeight());
        }
        poolSummaryDto.setEnding(ending);
    }

    //设置期末状态
    private void setPreEnd(PoolSummaryDto poolSummaryDto, CurPool curPool) {
        poolSummaryDto.setEndType(curPool.getType());
        Ending ending = new Ending();
        ending.setAmount(curPool.getQuantity());
        ending.setWeight(curPool.getWeight());
        if (curPool.getWeight() == 0 || curPool.getQuantity() == 0){
            ending.setSize(0.0);
        } else {
            ending.setSize(curPool.getQuantity()/ curPool.getWeight());
        }
        poolSummaryDto.setEnding(ending);
    }

    @Override
    public List<SiteSummaryDto> SiteSummary(List<String> siteNos, Date startDate, Date endDate) {
        if (siteNos == null || siteNos.size() == 0){
            siteNos = siteService.getAllSiteNo();
        }
        LinkedList<SiteSummaryDto> list = new LinkedList<>();

        //遍历场号
        for (String siteNo : siteNos) {
            //初始化新旧鳗苗汇总数据
            SiteSummaryDto newSiteSummaryDto = initSiteSummaryDto(siteNo, 1);
            SiteSummaryDto oldSiteSummaryDto = initSiteSummaryDto(siteNo, 2);
            //加入列表
            list.add(newSiteSummaryDto);
            list.add(oldSiteSummaryDto);

            //查询该场的全部塘号
            List<String> poolNos = siteService.getPoolsBySiteNo(siteNo);

            //期初数、期末存塘
            setSiteStartEnd(newSiteSummaryDto, startDate, endDate, 1);
            setSiteStartEnd(oldSiteSummaryDto, startDate, endDate, 2);

            //本期投喂增重、日常损耗
            setFeedGainWeightAndLoss(newSiteSummaryDto, startDate, endDate, 1, poolNos);
            setFeedGainWeightAndLoss(oldSiteSummaryDto, startDate, endDate, 2, poolNos);



            //新苗投塘
            setNewSeedLings(newSiteSummaryDto, startDate, endDate, 1, poolNos);
            setNewSeedLings(oldSiteSummaryDto, startDate, endDate, 2, poolNos);

            //本期发生

            //销售
            setSale(newSiteSummaryDto, startDate, endDate, 1, poolNos);
            setSale(oldSiteSummaryDto, startDate, endDate, 2, poolNos);

            //分塘
            setDivide(newSiteSummaryDto, startDate, endDate, 1, poolNos);
            setDivide(oldSiteSummaryDto, startDate, endDate, 2, poolNos);


            //清塘亏损
            setCleanLoss(newSiteSummaryDto, startDate, endDate, 1, poolNos);
            setCleanLoss(oldSiteSummaryDto, startDate, endDate, 2, poolNos);
        }

        return list;
    }

    //初始化场的汇总数据
    private SiteSummaryDto initSiteSummaryDto(String siteNo,int type){
        SiteSummaryDto siteSummaryDto = new SiteSummaryDto();
        Site site = siteService.getSiteByNo(siteNo);
        siteSummaryDto.setArea(site.getArea());
        siteSummaryDto.setSiteNo(siteNo);
        siteSummaryDto.setKey(siteNo);
        if (type == 1){
            siteSummaryDto.setKey(siteNo + "-new");
        }else if (type == 2){
            siteSummaryDto.setKey(siteNo + "-old");
        }
        siteSummaryDto.setType(type);
        Beginning beginning = new Beginning();
        beginning.setAmount(0);
        beginning.setWeight(0.0);
        beginning.setSize(0.0);
        siteSummaryDto.setBeginning(beginning);
        FeedGainWeight feedGainWeight = new FeedGainWeight();
        feedGainWeight.setFeed(0.0);
        feedGainWeight.setCoefficient(0.0);
        feedGainWeight.setGainWeight(0.0);
        siteSummaryDto.setFeedGainWeight(feedGainWeight);
        NewSeedLings newSeedLings = new NewSeedLings();
        newSeedLings.setAmount(0);
        newSeedLings.setWeight(0.0);
        siteSummaryDto.setNewSeedLings(newSeedLings);
        HappenedInPeriod happenedInPeriod = new HappenedInPeriod();
        Transfer transfer = new Transfer();
        transfer.setAmount(0);
        transfer.setWeight(0.0);
        happenedInPeriod.setTransfer(transfer);
        SummarySale sale = new SummarySale();
        sale.setAmount(0);
        sale.setWeight(0.0);
        happenedInPeriod.setSummarySale(sale);
        SaleA saleA = new SaleA();
        saleA.setAmount(0);
        saleA.setWeight(0.0);
        happenedInPeriod.setSaleA(saleA);
        siteSummaryDto.setHappenedInPeriod(happenedInPeriod);
        DailyLoss dailyLoss = new DailyLoss();
        dailyLoss.setAmount(0);
        dailyLoss.setWeight(0.0);
        siteSummaryDto.setDailyLoss(dailyLoss);
        CleanLoss cleanLoss = new CleanLoss();
        cleanLoss.setAmount(0);
        cleanLoss.setWeight(0.0);
        siteSummaryDto.setCleanLoss(cleanLoss);
        Ending ending = new Ending();
        ending.setAmount(0);
        ending.setWeight(0.0);
        ending.setSize(0.0);
        siteSummaryDto.setEnding(ending);
        return siteSummaryDto;
    }

    //期初期末状态
    private void setSiteStartEnd(SiteSummaryDto siteSummaryDto, Date startDate, Date endDate,int type) {
        //期初状态
        Beginning beginning = siteSummaryDto.getBeginning();
        QueryWrapper<HisPool> wrapper = new QueryWrapper<>();
        wrapper.eq("site_no", siteSummaryDto.getSiteNo());
        wrapper.eq("date", startDate);
        wrapper.eq("type", type);
        List<HisPool> list = hisPoolService.list(wrapper);
        for (HisPool hisPool : list) {
            beginning.setAmount(beginning.getAmount() + hisPool.getQuantity());
            beginning.setWeight(beginning.getWeight() + hisPool.getWeight());
        }
        if (beginning.getWeight() == 0 || beginning.getAmount() == 0) {
            beginning.setSize(0.0);
        } else {
            beginning.setSize(beginning.getAmount() / beginning.getWeight());
        }

        //期末状态
        Ending ending = siteSummaryDto.getEnding();
        wrapper = new QueryWrapper<>();
        wrapper.eq("site_no", siteSummaryDto.getSiteNo());
        wrapper.eq("date", endDate);
        wrapper.eq("type", type);
        if (IsToday.isToday(endDate)) {
            QueryWrapper<CurPool> q = new QueryWrapper<>();
            q.eq("site_no", siteSummaryDto.getSiteNo());
            q.eq("type", type);
            List<CurPool> list1 = curPoolService.list(q);
            for (CurPool curPool : list1) {
                ending.setAmount(ending.getAmount() + curPool.getQuantity());
                ending.setWeight(ending.getWeight() + curPool.getWeight());
            }
            if (ending.getWeight() == 0 || ending.getAmount() == 0) {
                ending.setSize(0.0);
            } else {
                ending.setSize(ending.getAmount() / ending.getWeight());
            }
        } else {
            list = hisPoolService.list(wrapper);
            for (HisPool hisPool : list) {
                ending.setAmount(ending.getAmount() + hisPool.getQuantity());
                ending.setWeight(ending.getWeight() + hisPool.getWeight());
            }
            if (ending.getWeight() == 0 || ending.getAmount() == 0) {
                ending.setSize(0.0);
            } else {
                ending.setSize(ending.getAmount() / ending.getWeight());
            }
        }

    }

    //本期投喂增重、日常损耗
    private void setFeedGainWeightAndLoss(SiteSummaryDto siteSummaryDto, Date startDate, Date endDate,int type,List<String> poolNos) {
        if (poolNos == null || poolNos.size() == 0){
            return;
        }
        FeedGainWeight feedGainWeight = siteSummaryDto.getFeedGainWeight();
        DailyLoss dailyLoss = siteSummaryDto.getDailyLoss();
        QueryWrapper<FeedLoss> wrapper = new QueryWrapper<>();
        wrapper.in("pool_no", poolNos);
        wrapper.between("date", startDate, endDate);
        wrapper.eq("type", type);
        List<FeedLoss> list = feedLossService.list(wrapper);

        if (type == 1){
            String s = baseDataService.selectValueByName("coefficient1");
            feedGainWeight.setCoefficient(Double.parseDouble(s));
        }else if (type == 2){
            String s = baseDataService.selectValueByName("coefficient2");
            feedGainWeight.setCoefficient(Double.parseDouble(s));
        }

        for (FeedLoss feedLoss : list) {
            feedGainWeight.setFeed(feedGainWeight.getFeed() + feedLoss.getFeed());
            feedGainWeight.setGainWeight(feedGainWeight.getFeed()/feedGainWeight.getCoefficient());
            dailyLoss.setAmount(dailyLoss.getAmount() + feedLoss.getLoss());
            dailyLoss.setWeight(dailyLoss.getWeight() + feedLoss.getLossWeight());
        }

    }

    //新苗投塘
    private void setNewSeedLings(SiteSummaryDto siteSummaryDto, Date startDate, Date endDate,int type, List<String> poolNos) {
        if (poolNos == null || poolNos.size() == 0){
            return;
        }
        NewSeedLings newSeedLings = siteSummaryDto.getNewSeedLings();
        QueryWrapper<Put> wrapper = new QueryWrapper<>();
        wrapper.in("pool_no", poolNos);
        wrapper.between("date", startDate, endDate);
        wrapper.eq("type", type);
        List<Put> list = putService.list(wrapper);
        for (Put put : list) {
            newSeedLings.setAmount(newSeedLings.getAmount() + put.getQuantity());
            newSeedLings.setWeight(newSeedLings.getWeight() + put.getWeight());
        }
        if (newSeedLings.getWeight() == 0 || newSeedLings.getAmount() == 0){
            newSeedLings.setSize(0.0);
        }else {
            newSeedLings.setSize(newSeedLings.getAmount() / newSeedLings.getWeight());
        }
    }

    //清塘亏损
    private void setCleanLoss(SiteSummaryDto siteSummaryDto, Date startDate, Date endDate,int type, List<String> poolNos) {
        if (poolNos == null || poolNos.size() == 0){
            return;
        }
        CleanLoss cleanLoss = siteSummaryDto.getCleanLoss();
        QueryWrapper<ClearLoss> wrapper = new QueryWrapper<>();
        wrapper.in("pool_no", poolNos);
        wrapper.between("date", startDate, endDate);
        wrapper.eq("type", type);
        List<ClearLoss> list = clearLossService.list(wrapper);
        for (ClearLoss clearLoss : list) {
            cleanLoss.setAmount(cleanLoss.getAmount() + clearLoss.getQuantity());
            cleanLoss.setWeight(cleanLoss.getWeight() + clearLoss.getWeight());
        }
    }

    //销售
    private void setSale(SiteSummaryDto siteSummaryDto, Date startDate, Date endDate,int type, List<String> poolNos) {
        if (poolNos == null || poolNos.size() == 0){
            return;
        }
        SummarySale summarySale = siteSummaryDto.getHappenedInPeriod().getSummarySale();
        SaleA saleA = siteSummaryDto.getHappenedInPeriod().getSaleA();
        QueryWrapper<Sale> wrapper = new QueryWrapper<>();
        wrapper.in("pool_no", poolNos);
        wrapper.between("date", startDate, endDate);
        wrapper.eq("type", type);
        wrapper.eq("sale_type", 0);
        List<Sale> list = saleService.list(wrapper);
        for (Sale sale : list) {
            summarySale.setAmount(summarySale.getAmount() + sale.getQuantity());
            summarySale.setWeight(summarySale.getWeight() + sale.getWeight());
        }
        if (summarySale.getWeight() == 0 || summarySale.getAmount() == 0){
            summarySale.setSize(0.0);
        }else {
            summarySale.setSize(summarySale.getAmount() / summarySale.getWeight());
        }
        wrapper = new QueryWrapper<>();
        wrapper.in("pool_no", poolNos);
        wrapper.between("date", startDate, endDate);
        wrapper.eq("type", type);
        wrapper.eq("sale_type", 1);
        list = saleService.list(wrapper);
        for (Sale sale : list) {
            saleA.setAmount(saleA.getAmount() + sale.getQuantity());
            saleA.setWeight(saleA.getWeight() + sale.getWeight());
        }
    }

    //分塘
    private void setDivide(SiteSummaryDto siteSummaryDto, Date startDate, Date endDate,int type, List<String> poolNos) {
        if (poolNos == null || poolNos.size() == 0){
            return;
        }
        Transfer transfer = siteSummaryDto.getHappenedInPeriod().getTransfer();
        QueryWrapper<Divide> wrapper = new QueryWrapper<>();
        wrapper.in("pool_no", poolNos);
        wrapper.between("date", startDate, endDate);
        wrapper.eq("type", type);
        wrapper.eq("divide_type", 0);
        List<Divide> list = divideService.list(wrapper);
        for (Divide divide : list) {
            transfer.setAmount(transfer.getAmount() + divide.getQuantity());
            transfer.setWeight(transfer.getWeight() + divide.getWeight());
        }
        wrapper = new QueryWrapper<>();
        wrapper.in("pool_no", poolNos);
        wrapper.between("date", startDate, endDate);
        wrapper.eq("type", type);
        wrapper.eq("divide_type", 1);
        list = divideService.list(wrapper);
        for (Divide divide : list) {
            transfer.setAmount(transfer.getAmount() - divide.getQuantity());
            transfer.setWeight(transfer.getWeight() - divide.getWeight());
        }
    }
}
